package provide generators 1.0
#package require Tk
#package require utils

set RESOURCE_DIR "../shared/resources"
 

Class SimulationRunner

# -------------------------------------------------------------------------------------
# Prepare the simulation. Insert to ns all the simulation details, before calling ns.run
SimulationRunner instproc simulate { scenarioFileName traceOutputFileName } {
	global RESOURCE_DIR
	# Constants
	$self set logFile [open "$RESOURCE_DIR/ns2.log" "w"]
	$self set trafficPacketSize 200
	$self set trafficIdle 0.01s
	$self set trafficBurst 0.1s
	$self set trafficRate 100K
	$self set linkBandwidth 1Mb
	# Delay is in milliseconds (adding the ms later to enable calculations)
	$self set linkDelay 100 
	$self set linkQueueType DropTail
	
	# Members 
	$self set ns [new Simulator]	
	$self set traceFile [open $traceOutputFileName w]
	$self set namFileName "${RESOURCE_DIR}/exp.nam.tr"
	$self set namTraceFile [open [$self set namFileName] w]
	[$self set ns] trace-all [$self set traceFile]
	[$self set ns] namtrace-all [$self set namTraceFile]	
	$self generatedTopology $scenarioFileName

	# Create output files
	$self instvar generators
	$self instvar outFiles
	$self instvar logFile
	
	if { [$self set recordBandwidth]=="true" } {
		array set outFiles []	
		for {set i 0} {$i < [array size generators]} {incr i} {
			puts "Created output file out$i.tr"
	      set outFiles($i) [open "${RESOURCE_DIR}/out$i.tr" w]	
	   }
   }
	$self setupRuntimes 1 5 7

	close $logFile	
}


# -------------------------------------------------------------------------------------
# Attaches an exponential traffic generator to a source and sink nodes
SimulationRunner instproc attach-expoo-traffic { source target} {
#Create an Expoo traffic agent and set its configuration parameters
	set traffic [new Application/Traffic/Exponential]
	$traffic set packetSize_ [$self set trafficPacketSize]
	$traffic set burst_time_ [$self set trafficIdle]
	$traffic set idle_time_ [$self set trafficBurst]
	$traffic set rate_ [$self set trafficRate]
   
#   set traffic [new Application/Traffic/CBR]
#   $traffic set packetSize_  [$self set trafficPacketSize]
#	$traffic set interval_ [$self set trafficIdle]
	
  	# Attach traffic source to the traffic generator
  	$traffic attach-agent $source
		
	#Connect the source and the sink
	[$self set ns] connect $source $target	
   return $traffic
}


# -------------------------------------------------------------------------------------
# Sets the start, end and finish time of the traffic generators
SimulationRunner instproc setupRuntimes { startTime endTime finishTime } {
	$self instvar generators
	$self instvar logFile	


	if { [$self set recordBandwidth]=="true" } {
		[$self set ns] at 0.0 "$self record"
	}	
	
	for {set i 0} {$i< [array size generators]} {incr i} {
		puts $logFile "Set start time ($startTime) and end time ($endTime) for generator $i"
		[$self set ns] at $startTime "$generators($i) start"
		[$self set ns] at $endTime "$generators($i) stop"
	}
	[$self set ns] at $finishTime "finish"
}

# -------------------------------------------------------------------------------------
# Finish
SimulationRunner instproc finish {} {
	$self instvar ns
	$self instvar traceFile
	$self instvar namTraceFile
	$self instvar namFileName
	$self instvar outFiles
	
	#Flush the trace
	$ns flush-trace
	
   #Close the output files
   if { [$self set recordBandwidth]=="true" } {   	
		for {set i 0} {$i < [array size outFiles]} {incr i} {
	   	close $outFiles($i)	
		}
	}
	close $traceFile
	close $namTraceFile
	#Write delay summary
	
	
   #Call xgraph to display the results
   #exec xgraph out0.tr out1.tr out2.tr -geometry 800x400 &
	if { [$self set showNam]=="true" } {
		exec nam $namFileName &
	}
   exit 0
}

# -------------------------------------------------------------------------------------
# Record the average bitrate 
SimulationRunner instproc record {} {
	$self instvar ns
	$self instvar outFiles
	$self instvar targets

	#Set the time after which the procedure should be called again
   set time 0.5

   #How many bytes have been received by the traffic sinks?
   for {set i 0} {$i < [array size outFiles]} {incr i} {
		set bw($i) [$targets($i) set bytes_]	
   }
	
   #Get the current time
   set now [$ns now]
	
   #Calculate the bandwidth (in MBit/s) and write it to the files
   for {set i 0} {$i < [array size outFiles]} {incr i} {	
		puts $outFiles($i) "$now [expr $bw($i)/$time*8/1000000]"
   }			

   #Reset the bytes_ values on the traffic sinks
   #Calculate the bandwidth (in MBit/s) and write it to the files
   for {set i 0} {$i < [array size targets]} {incr i} {
		$targets($i) set bytes_ 0
   }

   #Re-schedule the procedure
   $ns at [expr $now+$time] "record"
}

# -------------------------------------------------------------------------------------
# Sets a flag for showing/not showing NAM when finished
SimulationRunner instproc setShowNam { isShowNam } {
	$self set showNam $isShowNam
}

# Sets a flag for recording/not recording recieved bandwidth
SimulationRunner instproc setRecordBandwidth { isRecordBandwidth } {
	$self set recordBandwidth $isRecordBandwidth
}

# -------------------------------------------------------------------------------------
# Generate a topology 
SimulationRunner instproc generatedTopology {fileName} {
	$self instvar sources
	$self instvar targets
	$self instvar generators
	$self instvar logFile
	
	array set sources []
	array set targets []
	array set generators []

	set configFile [open $fileName r]

	# Generate nodes
	gets $configFile line
	if { [string match "*nodes*" $line]==0 } {
		puts "ERROR no node!"
		exit
	}
	gets $configFile line
	set numOfNodes $line
	puts $logFile "Creating $numOfNodes nodes..."
	
	# Create the nodes	
	for {set i 0} {$i < $numOfNodes} {incr i} {
  		set nodes($i) [[$self set ns] node]
		set delays($i) 0
		puts $logFile "Added node $i"
	}
	
	# Set delay dictionary if delays were set
	gets $configFile line
	if { [string match "*delays*" $line]!=0 } {
		gets $configFile line
		while { [string match "*edges*" $line]==0 } {
			set parts [split $line ","]
         set delayedNode [lindex $parts 0]
         set delay [lindex $parts 1]
			set delays($delayedNode) $delay			
			puts $logFile "Added {$delay}ms to node $delayedNode"
   		# Read next line
   		gets $configFile line	 			
		}
	}
	
	# Create the edges	
	if { [string match "*edges*" $line]==0 } {
		puts "ERROR no edges!"
		exit
	}	
	
	puts $logFile "Parsing edges..."	
   while {-1 != [gets $configFile line]} {
		if { [string match "*generators*" $line]!=0 } {
			puts $logFile "Parsing generators..."
			break
   	}		
				
		set edgePoints [split $line ","]
		set from [lindex $edgePoints 0]
		set to [lindex $edgePoints 1]
		set delay [$self set linkDelay]
		if { [string length [string trim [lindex $edgePoints 2]]] != 0 } {
			set delay [string trim [lindex $edgePoints 2]]
			puts $logFile "Added predefined delay $delay" 
		}
		
		# Add delays cause by nodes 
		set delay [expr $delay+$delays($from)+$delays($to)]ms	

		puts $logFile "($from -> $to) Link params [$self set linkBandwidth] $delay [$self set linkQueueType]"
		[$self set ns] duplex-link $nodes($from) $nodes($to) [$self set linkBandwidth] $delay [$self set linkQueueType]

   }
	
	set i 0
	while {-1 != [gets $configFile line]} {			
		set edgePoints [split $line ","]
		set from [lindex $edgePoints 0]
		set to [lindex $edgePoints 1]
		
		# Create the traffic generator
		set sources($i) [new Agent/UDP]	
		[$self set ns] attach-agent $nodes($from) $sources($i)
		set targets($i) [new Agent/LossMonitor]
		[$self set ns] attach-agent $nodes($to) $targets($i)
		
		puts $logFile "Adding traffic generators from $from to $to"
		set generators($i) [$self attach-expoo-traffic $sources($i) $targets($i)]
		
		# Color the agent's traffic in a unique color
   	$sources($i) set class_ $i
   	#[$self set ns] color $i [eval LightColor]		
		incr i
   }
}	


################# Non class functions ########
proc finish {} {
	global runMe	
	$runMe finish	
}


# Record the average bitrate 
proc record {} {
	global runMe
	$runMe record
}   
################# MAIN #######################